#ifndef SKYROAD_NETWARE_SVR_SERVER_H
#define SKYROAD_NETWARE_SVR_SERVER_H

#include <string>
#include <list>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio/io_service.hpp>
#include <skyroad/service/service.hpp>

#include "connection.hpp"
#include "connection_manager.hpp"
#include "request_handler.hpp"
#include "reply_dispatcher.hpp"

#define LOG4_INFO(info) LOG4CXX_INFO(log4cxx::Logger::getLogger("netware_svr"), info)

using namespace  boost;
using namespace  boost::asio;

class netw_server : public service
{
public:
    typedef service super;

    netw_server(bus& bus);
    ~netw_server();

    virtual void start();

    virtual void stop();
private:

    class worker : public boost::enable_shared_from_this<worker>
    {
    public:
        worker(io_service& io_service, ip::tcp::acceptor& acceptor, connection_manager& manager, request_handler& handler) 
            :m_io_service(io_service), 
            m_acceptor(acceptor),
            m_connection_manager(manager), 
            m_request_handler(handler),
            m_new_connection(new connection(m_io_service, m_connection_manager, m_request_handler))
        {

        }

        /// Handle completion of an asynchronous accept operation.
        void handle_accept(const system::error_code& e)
        {
            if (!m_new_connection.get())
            {
                return;
            }
            if (!e) 
            {
                m_new_connection->socket().set_option(ip::tcp::no_delay(true));
                m_new_connection->socket().set_option(socket_base::keep_alive(false));
                m_connection_manager.start(m_new_connection);
                m_new_connection.reset(new connection(m_io_service,m_connection_manager, m_request_handler));
            }
            else
            {

            }

            m_acceptor.async_accept( m_new_connection->socket(),
                                     boost::bind(&worker::handle_accept, this, asio::placeholders::error)
                                   );
        }

        void run()
        {
            int ncout =0;
            while (1) 
            {
                try
                {
                    m_new_connection.reset(new connection(m_io_service,m_connection_manager, m_request_handler));
                    m_acceptor.async_accept( m_new_connection->socket(),
                                             boost::bind(&worker::handle_accept, this,asio::placeholders::error)
                                           );
                    m_io_service.run();
                } 
                catch (std::exception& e)
                {
//                    srv_log_error(SRV_LOG_EMERG, mlog, 0, "worker error:%s", e.what());
                }
                catch (...)
                {
//                    srv_log_error(SRV_LOG_EMERG, mlog, 0, "worker error unknown");
                }
            }
        }
    private:
        io_service& m_io_service;
        ip::tcp::acceptor&   m_acceptor;
        request_handler& m_request_handler;
        connection_manager& m_connection_manager;
        connection_ptr m_new_connection;
    };

    typedef boost::shared_ptr<worker> worker_ptr;

    typedef boost::shared_ptr<boost::thread> thread_ptr;

    void run();

    /// Handle a request to stop the server.
    void handle_stop();

    virtual void handle_message(message& msg);

    bool m_active;

    std::list<thread_ptr> m_threads;
    std::list<worker_ptr> m_workers;

    // The io_service used to perform asynchronous operations.
    asio::io_service m_io_service;

    // Acceptor used to listen for incoming connections.
    asio::ip::tcp::acceptor m_acceptor;

    // The connection manager which owns all live connections.
    connection_manager m_connection_manager;

    ///The handler for all incoming requests.
    request_handler m_request_handler;

    // The diaptcher for all outgoing replys.
    reply_dispatcher m_reply_dispatcher;

    friend class request_handler;
 };
#endif
 

